<template>
  <div class = "tags-view-container">
    <scroll-panel>
      <div class = "tags-view-wrapper">
        <!-- 一个个tag view就是router-link -->
        <router-link
            class = "tags-view-item"
            :class = "{
              active: isActive(tag)
            }"
            :style = "{
              backgroundColor: isActive(tag) ? themeColor : '',
              borderColor: isActive(tag) ? themeColor : ''
            }"
            v-for = "(tag, index) in visitedTags"
            :key = "index"
            :to = "{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
            tag = "span"
        >
          <el-dropdown
              trigger = "contextmenu"
              @command = "command => handleTagCommand(command, tag)">
              <span>
                {{ tag.meta.title }}
                <!-- affix固定的路由tag是无法删除 -->
                <span
                    v-if = "!isAffix(tag)"
                    class = "el-icon-close"
                    @click.prevent.stop = "closeSelectedTag(tag)"
                ></span>
              </span>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item command = "refresh">刷新</el-dropdown-item>
                <el-dropdown-item command = "all">关闭所有</el-dropdown-item>
                <el-dropdown-item command = "other">关闭其他</el-dropdown-item>
                <el-dropdown-item command = "self" v-if = "!tag.meta || !tag.meta.affix">关闭</el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </router-link>
      </div>
    </scroll-panel>
  </div>
</template>

<script lang = "ts">
import { computed, defineComponent, nextTick, onMounted, watch } from 'vue'
import { useStore } from '@/store'
import { RouteRecordRaw, useRoute, useRouter } from 'vue-router'
import {
  ADD_VISITED_VIEW,
  DEL_VISITED_VIEW,
  DEL_ALL_VIEWS,
  DEL_OTHER_VISITED_VIEWS,
  DEL_CACHE_VIEW
} from '@/store/modules/methods-type'
import path from 'path'
import { RouteLocationWithFullPath } from '@/store/modules/tagsView'
import { routes } from '@/router'
import ScrollPanel from '@/components/ScrollPanel/index.vue'

enum TagCommandType {
  All = 'all',
  Other = 'other',
  Self = 'self',
  Refresh = 'refresh'
}

export default defineComponent({
  name: 'TagsView',
  components: {
    ScrollPanel
  },
  setup() {
    const store = useStore(),
        route = useRoute(),
        router = useRouter(),
        visitedTags = computed(() => store.getters.tagsView)

    const addTags = () => {
      const { name } = route
      if ( name ) store.dispatch(`tagsView/${ ADD_VISITED_VIEW }`, route)
    }

    /* 监听路径发生变化的时候 追加tag view */
    watch(() => route.path, () => addTags())

    /* 从路由表中过滤出固定的tag */
    const fillterAffixTags = (routes: Array<RouteLocationWithFullPath | RouteRecordRaw>, basePath = '/'): RouteLocationWithFullPath[] => {
      let tags: RouteLocationWithFullPath[] = []
      routes.forEach((item) => {
        if ( item.meta && item.meta.affix ) {
          const tagPath = path.resolve(basePath, item.path)
          tags.push({
            name: item.name,
            path: tagPath,
            fullPath: tagPath,
            meta: { ...item.meta }
          } as RouteLocationWithFullPath)
        }
        if ( item.children ) {
          const childTags = fillterAffixTags(item.children, item.path) || []
          if ( childTags.length ) {
            tags = [ ...tags, ...childTags ]
          }
        }
      })
      return tags
    }

    /* 初始化添加affix的tag */
    const initTags = () => {
      const affixTags = fillterAffixTags(routes)
      for ( const tag of affixTags ) {
        if ( tag.name ) store.dispatch(`tagsView/${ ADD_VISITED_VIEW }`, tag)
      }
    }

    /* 组件初期加载的时候 添加tag */
    onMounted(() => {
      initTags()
      addTags()
    })

    /* 是否是当前激活的tag */
    const isActive = (tag: RouteRecordRaw) => {
      return tag.path === route.path
    }

    /* 删除激活的tag后 集合中的最后一个设置为选中状态 */
    const toLastView = (visitedViews: RouteLocationWithFullPath[], view: RouteLocationWithFullPath) => {
      const lastView = visitedViews[visitedViews.length - 1]
      if ( lastView ) {
        router.push(lastView.fullPath as string)
        return
      }
      if ( view.name === 'Dashboard' ) {
        router.replace({ path: '/redirect' + view.fullPath as string })
        return
      }
      router.push('/')
    }

    /* 关闭当前右击tag路由 */
    const closeSelectedTag = (view: RouteLocationWithFullPath) => {
      store.dispatch(`tagsView/${ DEL_VISITED_VIEW }`, view).then(() => {
        /* 如果选中的激活的tag 继续下面的处理 */
        if ( !isActive(view) ) return
        toLastView(visitedTags.value, view)
      })
    }

    /* 判断是否始终固定在tagsView上的tag */
    const isAffix = (tag: RouteLocationWithFullPath) => {
      return tag.meta && tag.meta.affix
    }

    /* 表示右击菜单 */
    const handleTagCommand = (command: TagCommandType, view: RouteLocationWithFullPath): void => {
      switch ( command ) {
        case TagCommandType.All:
          handleCloseAllTag(view)
          break
        case TagCommandType.Other:
          handleCloseOtherTag(view)
          break
        case TagCommandType.Self:
          closeSelectedTag(view)
          break
        case TagCommandType.Refresh:
          refreshSelectedTag(view)
      }
    }

    /* 删除除了affix 为true的tag */
    const handleCloseAllTag = (view: RouteLocationWithFullPath) => {
      store.dispatch(`tagsView/${ DEL_ALL_VIEWS }`).then(() => {
        toLastView(visitedTags.value, view)
      })
    }

    /* 删除其他tag 除了当前右击的tag */
    const handleCloseOtherTag = (view: RouteLocationWithFullPath) => {
      store.dispatch(`tagsView/${ DEL_OTHER_VISITED_VIEWS }`, view).then(() => {
        if ( !isActive(view) ) router.push(view.path)
      })
    }

    /* 表示右击刷新 清空当前对应的路由缓存 */
    const refreshSelectedTag = (view: RouteLocationWithFullPath) => {
      store.dispatch(`tagsView/${ DEL_CACHE_VIEW }`, view).then(() => {
        const { fullPath } = view
        nextTick(() => {
          router.replace(`/redirect${ fullPath }`)
        })
      })
    }

    /* 获取模板颜色 */
    const themeColor = computed(() => store.getters.themeColor)

    return {
      visitedTags,
      isActive,
      closeSelectedTag,
      isAffix,
      handleTagCommand,
      themeColor
    }
  }
})
</script>

<style lang = "scss" scoped>
.tags-view-container {
  overflow: hidden;
  height: 34px;
  background: #fff;
  border-bottom: 1px solid #d8dce5;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);

  .tags-view-wrapper {
    display: flex;

    .tags-view-item {
      display: inline-block;
      height: 26px;
      line-height: 26px;
      border: 1px solid #d8dce5;
      background: #fff;
      color: #495060;
      padding: 0 8px;
      box-sizing: border-box;
      font-size: 12px;
      margin-left: 5px;
      margin-top: 4px;

      &:first-of-type {
        margin-left: 15px;
      }

      &:last-of-type {
        margin-right: 15px;
      }

      &.active {
        background-color: #409eff;
        color: #fff;
        border-color: #409eff;

        &::before {
          position: relative;
          display: inline-block;
          content: '';
          width: 8px;
          height: 8px;
          border-radius: 50%;
          margin-right: 5px;
          background: #fff;
        }
      }
    }
  }
}

</style>

<style lang = "scss">
.tags-view-container {
  .el-icon-close {
    width: 16px;
    height: 16px;
    vertical-align: 2px;
    border-radius: 50%;
    text-align: center;
    transition: all .3s cubic-bezier(.645, .045, .355, 1);
    transform-origin: 100% 50%;

    &:before {
      transform: scale(.6);
      display: inline-block;
      vertical-align: -3px;
    }

    &:hover {
      background-color: #b4bccc;
      color: #fff;
    }
  }
}
</style>
